//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ListAncestorMol.h"

#include <string.h>
#include <stdlib.h>

#include <fstream>
#include <iostream>

#include <math.h>
#include <zlib.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGHTINLINE 500000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace SpaceListAncestor {

  bool AscendentAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    
    return (*(ancestorA->ListIdAncestor()->Get(level)) < *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
    
  }

  bool DescendentAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    
    return (*(ancestorA->ListIdAncestor()->Get(level)) > *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
    
  }

  bool EqualAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    
    return (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
    
  }

  bool EqualAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameterA, void* parameterB) {
    
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          levelA     = (*(int*)parameterA) - 1;
    int          levelB     = (*(int*)parameterB) - 1;
    
    return (*(ancestorA->ListIdAncestor()->Get(levelA)) == *(ancestorB->ListIdAncestor()->Get(levelB)))?true:false;
    
  }

  bool DiffAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;

    if (*(ancestorA->ListIdAncestor()->Get(level)) != *(ancestorB->ListIdAncestor()->Get(level))) 
      return false;

    if (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorA->ListIdAncestor()->Get(0))) {
      NodeT->Info(NULL);
      NodeT->Info(ancestorB);
      ((TNode <AncestorMol>*)ref)->Info(NULL);
      ((TNode <AncestorMol>*)ref)->Info(ancestorA);
    }
    
    return true;
    
  }

  bool EqualParents(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    
    return (*(ancestorA->ListIdAncestor()->Get(0)) == *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
    
  }

  bool EqualChildren(TNode <AncestorMol>* NodeT, void* ref) {
    
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    
    return (*(ancestorA->ListIdAncestor()->Get(0)) == *(ancestorB->ListIdAncestor()->Get(0)))?true:false;
    
  }

  double ComputeMatrixSim(TNode <String>* NodeT, void* ref, void* parameters) {
    
    if (!parameters) return 0;
    
    String*     elementA  = NodeT->Info();
    String*     elementB  = ((TNode <String>*)ref)->Info();
    double      value     = 0;
    
    ((MatrixTool*)parameters)->ValuePosition(elementA, elementB, value);
    
    return value;
    
  }

};

namespace SpaceString {
  
  bool AscendentString(TNode <String>* NodeT, void* ref) {
    
    String* stringA  = NodeT->Info();
    String* stringB  = ((TNode <String>*)ref)->Info();
    
    return (*stringA < *stringB)?true:false;
    
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::ListAncestorMol() {
  
  this->filenameAncestor = new String ();
  this->listAncestor     = new TListE <AncestorMol> ();
  this->similarityMatrix = NULL;   
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::ListAncestorMol(String* filenameAncestor) {
  
  this->filenameAncestor = new String (filenameAncestor);
  this->listAncestor     = new TListE <AncestorMol> ();
  this->similarityMatrix = NULL;   
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::ListAncestorMol(ListAncestorMol& listAncestorMol) {
  
  this->filenameAncestor = new String (listAncestorMol.filenameAncestor);
  this->listAncestor     = new TListE <AncestorMol> (listAncestorMol.listAncestor);
  this->similarityMatrix = listAncestorMol.similarityMatrix;   
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::ListAncestorMol(ListAncestorMol* listAncestorMol) {
  
  this->filenameAncestor = new String (listAncestorMol->filenameAncestor);
  this->listAncestor     = new TListE <AncestorMol> (listAncestorMol->listAncestor);
  this->similarityMatrix = listAncestorMol->similarityMatrix;   
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::~ListAncestorMol() {
  
  if (this->filenameAncestor) delete this->filenameAncestor;
  if (this->listAncestor)     delete this->listAncestor;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::FilenameAncestor(String* filenameAncestor) {
  this->filenameAncestor->In(filenameAncestor);
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::FilenameAncestor(char* filenameAncestor) {
  this->filenameAncestor->In(filenameAncestor);
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::ListAncestor(TListE <AncestorMol>* listAncestor) {
  *(this->listAncestor) = *listAncestor;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::MatrixSimilarity(MatrixTool* matrixSimilarity) {
  this->similarityMatrix = similarityMatrix;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ListAncestorMol::FilenameAncestor(void) {
  return this->filenameAncestor;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <AncestorMol>* ListAncestorMol::ListAncestor(void) {
  return this->listAncestor;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
MatrixTool* ListAncestorMol::MatrixSimilarity(void) {
  return this->similarityMatrix;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::SetListAncestor(TListE <String>* listAncestor) {
  
  if (!listAncestor) return false;
  
  this->listAncestor->Clear();
  
  listAncestor->SetInitial();
  while (listAncestor->SetNext()) {
    
    AncestorMol* ancestor = new AncestorMol ();
    ancestor->ListIdAncestor()->Add(new String (listAncestor->GetCurrent()));
    this->listAncestor->Add(ancestor);
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::LoadDataAncestorFiles(void) {
  
  if (!this->filenameAncestor->Length()) return false;

  ifstream ancestorFile;
  gzFile   ancestorFileGZ;
  
  String   lineInput;
  
  bool     fileIsGZ = (this->filenameAncestor->Contain("gz"))?true:false;

  if (!fileIsGZ) ancestorFile.open(this->filenameAncestor->Out(), ios::in);
  else           ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "rb9");
  
  this->listAncestor->Clear();

  while (!((!fileIsGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!fileIsGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else           gzgets(ancestorFileGZ, buffer, LENGHTINLINE);
    
    lineInput.In(buffer); lineInput.Trim();
    
    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol ();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      this->listAncestor->Add(ancestorMol);
      
    }
    
  }
  
  if (!fileIsGZ) ancestorFile.close();
  else           gzclose(ancestorFileGZ);

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::LoadDataAncestorFilesFrom(long begin, long end) {

  if (!this->filenameAncestor->Length()) return false;

  ifstream ancestorFile;
  gzFile   ancestorFileGZ;

  String   lineInput;
  
  bool     fileIsGZ = (this->filenameAncestor->Contain("gz"))?true:false;

  if (!fileIsGZ) {
    ancestorFile.open(this->filenameAncestor->Out(), ios::in);
    ancestorFile.seekg(begin, ios::beg);
  }
  else {
    ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "rb9");
    gzseek(ancestorFileGZ, begin, SEEK_SET);
  }

  this->listAncestor->Clear();

  while (!((!fileIsGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!fileIsGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else           gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol ();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      this->listAncestor->Add(ancestorMol);

    }
    
    if (!fileIsGZ) { if (ancestorFile.tellg()   > end) break; }
    else           { if (gztell(ancestorFileGZ) > end) break; }

  }

  if (!fileIsGZ) ancestorFile.close();
  else           gzclose(ancestorFileGZ);

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::AddAncestorFromFile(String* filename, int level) {
  
  if (!filename || !filename->Length() || level < 0 || level >= this->listAncestor->GetFirst()->ListIdAncestor()->Length()) 
    return false;

  ifstream      ancestorFile;
  gzFile        ancestorFileGZ;
  
  String        lineInput;
  AncestorMol*  ancestorMol = new AncestorMol ();
  
  bool          fileIsGZ    = (filename->Contain("gz"))?true:false;

  if (!fileIsGZ) ancestorFile.open(filename->Out(), ios::in);
  else           ancestorFileGZ = gzopen(filename->Out(), "rb9");
  
  while (!((!fileIsGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!fileIsGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else           gzgets(ancestorFileGZ, buffer, LENGHTINLINE);
    
    lineInput.In(buffer); lineInput.Trim();
    
    if (lineInput.Length()) {

      ancestorMol->InputLineAncestor(lineInput);
      
      this->listAncestor->SetInitial();
      while (this->listAncestor->SetNext()) 
        if (*(this->listAncestor->GetCurrent()->ListIdAncestor()->Get(level)) == *(ancestorMol->ListIdAncestor()->Get(0))) {
          String *newAncestor = new String (ancestorMol->ListIdAncestor()->Get(1));
          this->listAncestor->GetCurrent()->ListIdAncestor()->Add(newAncestor);
        }

    }
    
  }
  
  if (!fileIsGZ) ancestorFile.close();
  else           gzclose(ancestorFileGZ);
  
  if (ancestorMol) delete ancestorMol;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::WriteAncestorFile(void) {

  fstream ancestorFile;
  gzFile  ancestorFileGZ;
  
  bool    fileIsGZ = (this->filenameAncestor->Contain("gz"))?true:false;

  if (!fileIsGZ) ancestorFile.open(this->filenameAncestor->Out(), ios::out);
  else           ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "wb9");

  this->listAncestor->SetInitial();

  while (this->listAncestor->SetNext()) {

    char* textOut = this->listAncestor->GetCurrent()->OutToAncestorString();

    if (!fileIsGZ) ancestorFile << textOut << endl;
    else           gzprintf(ancestorFileGZ, "%s\n", textOut);

    if (textOut) delete[] textOut;

  }

  if (!fileIsGZ) ancestorFile.close();
  else           gzclose(ancestorFileGZ);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::WriteAncestorFileFrom(long begin, long amount) {

  fstream ancestorFile;
  gzFile  ancestorFileGZ;
  
  long    count    = 0;
  
  bool    fileIsGZ = (this->filenameAncestor->Contain("gz"))?true:false;

  if (!fileIsGZ) ancestorFile.open(this->filenameAncestor->Out(), ios::out);
  else           ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "wb9");

  this->listAncestor->SetPosition(begin);

  while (this->listAncestor->SetNext()) {

    char* textOut = this->listAncestor->GetCurrent()->OutToAncestorString();

    if (!fileIsGZ) ancestorFile << textOut << endl;
    else           gzprintf(ancestorFileGZ, "%s\n", textOut);

    if (textOut) delete[] textOut;
    if (count++ > amount) break;

  }

  if (!fileIsGZ) ancestorFile.close();
  else           gzclose(ancestorFileGZ);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorCenteredMatrixIterative(void) { 
  
  int                   level              = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  TListE <AncestorMol>* repreAncestorList  = new TListE <AncestorMol> ();
  TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();

  this->listAncestor->RepresentativeOcurrences(SpaceListAncestor::DiffAncestor, repreAncestorList, &level);

  this->ListOriginalAncestor(repreAncestorList, representativeList, level);

  repreAncestorList->TransferAll();
  if (repreAncestorList) delete repreAncestorList;

  this->CenterListByMatrix(representativeList, NULL);

  this->listAncestor->OrderListByList(SpaceListAncestor::EqualAncestor, representativeList, &level);

  for (long i = level; i > 1; i--) {

    level--;

    if (i != this->listAncestor->GetFirst()->ListIdAncestor()->Length()) {
      
      TListE <AncestorMol>* repreAncestorList  = new TListE <AncestorMol> ();

      this->listAncestor->RepresentativeOcurrences(SpaceListAncestor::EqualAncestor, repreAncestorList, &i);

      this->ListOriginalAncestor(repreAncestorList, representativeList, i);

      repreAncestorList->TransferAll();
      if (repreAncestorList) delete repreAncestorList;
      
    }
    
    if (representativeList->Length()) {

      representativeList->SetInitial();

      while (representativeList->SetNext()) {

        TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

        this->listAncestor->ConsecutiveSubList(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &i);

        if (childrenList->Length()) {

          TListE <AncestorMol>* representativeChildrenList  = new TListE <AncestorMol> ();

          if (level > 1) {
            
            TListE <AncestorMol>* repreChildrenAncestorList  = new TListE <AncestorMol> ();

            childrenList->RepresentativeOcurrences(SpaceListAncestor::EqualAncestor, repreChildrenAncestorList, &level);

            this->ListOriginalAncestor(repreChildrenAncestorList, representativeChildrenList, level);

            repreChildrenAncestorList->TransferAll();
            if (repreChildrenAncestorList) delete repreChildrenAncestorList;
            
          }
          else *(representativeChildrenList) = *(childrenList);

          this->CenterListByMatrix(representativeChildrenList, representativeList->GetCurrent()->ListIdAncestor()->GetFirst());

          childrenList->OrderListByList(SpaceListAncestor::EqualAncestor, representativeChildrenList, &level);

          representativeChildrenList->TransferAll();
          if (representativeChildrenList) delete representativeChildrenList;

          childrenList->CleanConsecutiveSubList();

        }

        if (childrenList) delete childrenList;

      }

    }

    representativeList->TransferAll();

  }
  
  if (representativeList) delete representativeList;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorCenteredMatrixIterativeX(void) { 

  int                   level              = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  int                   size               = level;
  TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();

  this->listAncestor->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &size);
  this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeList, &size);

  this->CenterListByMatrix(representativeList, NULL);
  this->listAncestor->OrderListByList(SpaceListAncestor::EqualAncestor, representativeList, &size);

  for (long i = level; i > 1; i--) {

    level--;

    if (representativeList->Length()) {

      representativeList->SetInitial();
      while (representativeList->SetNext()) {

        TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();
        this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &i);

        if (childrenList->Length() > 1) {

          TListE <AncestorMol>* representativeChildrenList  = new TListE <AncestorMol> ();
          int levelOrder = level - 1;
          if (level > 1) {
            childrenList->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &levelOrder);
            childrenList->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeChildrenList, &level);
          }
          else           *(representativeChildrenList) = *(childrenList);

          this->CenterListByMatrix(representativeChildrenList, representativeList->GetCurrent()->ListIdAncestor()->GetFirst());
          childrenList->OrderListByList(SpaceListAncestor::EqualAncestor, representativeChildrenList, &level);

          representativeChildrenList->TransferAll();
          if (representativeChildrenList) delete representativeChildrenList;

        }
        
        childrenList->TransferAll();
        if (childrenList) delete childrenList;
        
      }

    }

    representativeList->TransferAll();
    if (level > 1) this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeList, &i);

  }

  representativeList->TransferAll();
  if (representativeList) delete representativeList;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorAscendentIterative(void) {

  int level = this->listAncestor->GetFirst()->ListIdAncestor()->Length();

  this->listAncestor->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &level);

  for (int i = this->listAncestor->GetFirst()->ListIdAncestor()->Length(); i > 1; i--) {

    level--;
    TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();
    this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::EqualAncestor, representativeList, &i);

    if (representativeList->Length()) {

      representativeList->SetInitial();

      while (representativeList->SetNext()) {

        TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

        this->listAncestor->ConsecutiveSubList(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &i);

        if (childrenList->Length()) {
          childrenList->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &level);
          childrenList->CleanConsecutiveSubList();
        }

        if (childrenList) delete childrenList;

      }

      representativeList->TransferAll();

    }

    if (representativeList) delete representativeList;

  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorDescendentIterative(void) {

  int level = this->listAncestor->GetFirst()->ListIdAncestor()->Length();

  this->listAncestor->QuickSortList(SpaceListAncestor::DescendentAncestor, NULL, &level);

  for (int i = this->listAncestor->GetFirst()->ListIdAncestor()->Length(); i > 1; i--) {

    level--;
    TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();
    this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::EqualAncestor, representativeList, &i);

    if (representativeList->Length()) {

      representativeList->SetInitial();

      while (representativeList->SetNext()) {

        TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

        this->listAncestor->ConsecutiveSubList(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &i);
        
        if (childrenList->Length()) {
          childrenList->QuickSortList(SpaceListAncestor::DescendentAncestor, NULL, &level);
          childrenList->CleanConsecutiveSubList();
        }

        if (childrenList) delete childrenList;

      }

      representativeList->TransferAll();

    }

    if (representativeList) delete representativeList;

  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorCentered(void) { 

  int                   level              = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  TListE <AncestorMol>* repreAncestorList  = new TListE <AncestorMol> ();
  TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();

  this->listAncestor->RepresentativeOcurrences(SpaceListAncestor::EqualAncestor, repreAncestorList, &level);
  this->ListOriginalAncestor(repreAncestorList, representativeList, level);

  repreAncestorList->TransferAll();
  if (repreAncestorList) delete repreAncestorList;

  if (representativeList->Length()) {

    this->CenterListByMatrix(representativeList, NULL);
    this->listAncestor->OrderListByList(SpaceListAncestor::EqualAncestor, representativeList, &level);

    representativeList->SetInitial();

    while (representativeList->SetNext()) {

      TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

      this->listAncestor->ConsecutiveSubList(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &level);

      if (childrenList->Length()) {

        int levelBefore = level - 1;

        TListE <AncestorMol>* repreChildrenAncestorList  = new TListE <AncestorMol> ();
        childrenList->RepresentativeOcurrences(SpaceListAncestor::EqualAncestor, repreChildrenAncestorList, &levelBefore);

        TListE <AncestorMol>* representativeChildrenList  = new TListE <AncestorMol> ();
        this->ListOriginalAncestor(repreChildrenAncestorList, representativeChildrenList, levelBefore);

        repreChildrenAncestorList->TransferAll();
        if (repreChildrenAncestorList) delete repreChildrenAncestorList;

        this->CenterListByMatrix(representativeChildrenList, representativeList->GetCurrent()->ListIdAncestor()->GetFirst());

        childrenList->OrderListByList(SpaceListAncestor::EqualAncestor, representativeChildrenList, &levelBefore);

        representativeChildrenList->TransferAll();
        if (representativeChildrenList) delete representativeChildrenList;

        childrenList->CleanConsecutiveSubList();

      }

      if (childrenList) delete childrenList;

    }

  }

  representativeList->TransferAll();
  if (representativeList) delete representativeList;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::GetAncestorByLevel(TListE <String>* ancestors, int level) {
  
  if (!ancestors || level < 0 || level > this->listAncestor->GetFirst()->ListIdAncestor()->Length()) 
    return false;
  
  ancestors->Clear();
  
  this->listAncestor->SetInitial();
  while (this->listAncestor->SetNext()) {
    
    bool    found       = false;
    String* ancestorRef = (this->listAncestor->GetCurrent()->ListIdAncestor()->Length() > level)
                          ?this->listAncestor->GetCurrent()->ListIdAncestor()->Get(level):NULL;
    
    if (!ancestorRef) continue;
    
    if (!level) {
      ancestors->Add(new String (ancestorRef));
      continue;
    }
    
    ancestors->SetInitial();
    while (ancestors->SetNext()) 
      if ((*(ancestors->GetCurrent()) == *ancestorRef)) {
        found = true;
        break;
      }
    
    if (!found) 
      ancestors->Add(new String (ancestorRef));
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorAscendent(void) {

  int level = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  this->listAncestor->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &level);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorDescendent(void) {

  int level = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  this->listAncestor->QuickSortList(SpaceListAncestor::DescendentAncestor, NULL, &level);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeConvergenceAncestorFile(String* referenceFile) {

  if (!referenceFile->Length()) return 0;

  TListE <AncestorMol>* listReferenceAncestor = new TListE <AncestorMol> ();

  ifstream              ancestorFile;
  gzFile                ancestorFileGZ;

  bool                  refFileGZ             = (referenceFile->Contain("gz"))?true:false;
  
  String                lineInput;

  if (!refFileGZ) ancestorFile.open(referenceFile->Out(), ios::in);
  else            ancestorFileGZ = gzopen(referenceFile->Out(), "rb9");

  while (!((!refFileGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!refFileGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else            gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol ();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      listReferenceAncestor->Add(ancestorMol);

    }

  }

  if (!refFileGZ) ancestorFile.close();
  else            gzclose(ancestorFileGZ);

  double                factor  = 0;
  int                   level   = 2;

  TNode  <AncestorMol>* refNode = this->listAncestor->GetFirstNode();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {

    TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();
    
    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &level);

    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();

      listReferenceAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, refNode, &level);

      if (childrenRefList->Length()) {

        long commonMolecules = 0;
        
        TNode  <AncestorMol>* commonNode = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next())
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        factor += ((double)((double)commonMolecules/(double)childrenRefList->Length()));

        childrenRefList->TransferAll();

      }

      if (childrenRefList) delete childrenRefList;
       
      childrenList->TransferAll();
      
    }

    if (childrenList) delete childrenList;
    
  }

  factor /= ((double)listReferenceAncestor->Length());

  if (listReferenceAncestor) delete listReferenceAncestor;
  
  return factor;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeConvergenceClusterSim(String* referenceFile) {

  if (!referenceFile->Length()) return 0;

  TListE <AncestorMol>* listReferenceAncestor = new TListE <AncestorMol> ();

  ifstream              ancestorFile;
  gzFile                ancestorFileGZ;
  bool                  refFileGZ             = (referenceFile->Contain("gz"))?true:false;
  String                lineInput;

  if (!refFileGZ) ancestorFile.open(referenceFile->Out(), ios::in);
  else            ancestorFileGZ = gzopen(referenceFile->Out(), "rb9");

  while (!((!refFileGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!refFileGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else            gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol ();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      listReferenceAncestor->Add(ancestorMol);

    }

  }

  if (!refFileGZ) ancestorFile.close();
  else            gzclose(ancestorFileGZ);

  double                factorRef  = 0;
  double                factorOwn  = 0;
  int                   level      = 2;

  TNode  <AncestorMol>* refNode = this->listAncestor->GetFirstNode();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {
    
    TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();
    
    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &level);
    
    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();

      listReferenceAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, refNode, &level);

      if (childrenRefList->Length()) {

        long commonMolecules = 0;

        TNode  <AncestorMol>* commonNode = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next()) 
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        factorRef += ((commonMolecules - 1)/(childrenList->Length() + childrenRefList->Length() - commonMolecules));
        factorOwn += ((childrenList->Length() - 1)/(childrenList->Length()));

        childrenRefList->TransferAll();

      }
      else {

        factorRef += ((-1)/(childrenList->Length()));
        factorOwn += ((childrenList->Length() - 1)/(childrenList->Length()));
        
      }

      if (childrenRefList) delete childrenRefList;

      childrenList->TransferAll();

    }

    if (childrenList) delete childrenList;
    
  }

  if (listReferenceAncestor) delete listReferenceAncestor;

  return factorRef/factorOwn;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeSumConvergenceAncestorFile(String* referenceFile, long& numberCompounds) {

  if (!referenceFile->Length()) return 0;

  TListE <AncestorMol>* listReferenceAncestor = new TListE <AncestorMol> ();

  ifstream              ancestorFile;
  gzFile                ancestorFileGZ;

  bool                  refFileGZ             = (referenceFile->Contain("gz"))?true:false;

  String                lineInput;

  if (!refFileGZ) ancestorFile.open(referenceFile->Out(), ios::in);
  else            ancestorFileGZ = gzopen(referenceFile->Out(), "rb9");

  while (!((!refFileGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!refFileGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else            gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol ();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      listReferenceAncestor->Add(ancestorMol);

    }

  }

  if (!refFileGZ) ancestorFile.close();
  else            gzclose(ancestorFileGZ);

  double                factor  = 0;
  int                   level   = 2;

  TNode  <AncestorMol>* refNode = this->listAncestor->GetFirstNode();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {

    TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &level);

    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();

      listReferenceAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, refNode, &level);

      if (childrenRefList->Length()) {

        long commonMolecules = 0;

        TNode  <AncestorMol>* commonNode = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next())
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        factor += ((double)((double)commonMolecules/(double)childrenRefList->Length()));

        childrenRefList->TransferAll();

      }

      if (childrenRefList) delete childrenRefList;

      childrenList->TransferAll();

    }

    if (childrenList) delete childrenList;

  }

  numberCompounds = listReferenceAncestor->Length();

  if (listReferenceAncestor) delete listReferenceAncestor;

  return factor;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeSumConvergenceClusterSim(String* referenceFile, double& factorRef, double& factorOwn) {

  if (!referenceFile->Length()) return 0;

  TListE <AncestorMol>* listReferenceAncestor = new TListE <AncestorMol> ();

  ifstream              ancestorFile;
  gzFile                ancestorFileGZ;
  bool                  refFileGZ             = (referenceFile->Contain("gz"))?true:false;
  String                lineInput;

  if (!refFileGZ) ancestorFile.open(referenceFile->Out(), ios::in);
  else            ancestorFileGZ = gzopen(referenceFile->Out(), "rb9");

  while (!((!refFileGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!refFileGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else            gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol ();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      listReferenceAncestor->Add(ancestorMol);

    }

  }

  if (!refFileGZ) ancestorFile.close();
  else            gzclose(ancestorFileGZ);

  factorRef = 0;
  factorOwn = 0;
  
  int level = 2;

  TNode  <AncestorMol>* refNode = this->listAncestor->GetFirstNode();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {

    TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &level);

    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();

      listReferenceAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, refNode, &level);

      if (childrenRefList->Length()) {

        long commonMolecules = 0;

        TNode  <AncestorMol>* commonNode = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next())
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        factorRef += (double)((double)(commonMolecules - 1)/(double)(childrenList->Length() + childrenRefList->Length() - commonMolecules));
        factorOwn += (double)((double)(childrenList->Length() - 1)/(double)(childrenList->Length()));

        childrenRefList->TransferAll();

      }
      else {

        factorRef += ((double)(-1)/(double)(childrenList->Length()));
        factorOwn += ((double)(childrenList->Length() - 1)/(double)(childrenList->Length()));

      }

      if (childrenRefList) delete childrenRefList;

      childrenList->TransferAll();

    }

    if (childrenList) delete childrenList;

  }

  if (listReferenceAncestor) delete listReferenceAncestor;
  
  return factorRef/factorOwn;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeClusterSimilarity(String* referenceFile, int levelA, int levelB) {

  if (!referenceFile->Length()) return 0;

  ListAncestorMol* listReferenceAncestor = new ListAncestorMol ();

  listReferenceAncestor->FilenameAncestor(referenceFile);
  listReferenceAncestor->LoadDataAncestorFiles();

  double similarity = 0;

  TNode  <AncestorMol>* refNode      = this->listAncestor->GetFirstNode();
  TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {

    childrenList->TransferAll();
    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &levelA);

    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();
      TNode  <AncestorMol>* searchNode      = new TNode <AncestorMol> ();

      AncestorMol* searchMol = listReferenceAncestor->ListAncestor()->FirstOcurrence(SpaceListAncestor::EqualChildren, refNode);
      if (searchMol) {
        searchNode->Info(searchMol);
        listReferenceAncestor->ListAncestor()->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, searchNode, &levelB);
        searchNode->Info(NULL);
      }

      if (searchNode) delete searchNode;

      if (childrenRefList->Length()) {

        long                  commonMolecules = 0;
        TNode  <AncestorMol>* commonNode      = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next())
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        similarity += (double)((double)(commonMolecules)/(double)(childrenList->Length() + childrenRefList->Length() - commonMolecules));

        childrenRefList->TransferAll();

      }

      if (childrenRefList) delete childrenRefList;

      childrenList->TransferAll();

    }

  }

  if (childrenList)          delete childrenList;
  if (listReferenceAncestor) delete listReferenceAncestor;

  return similarity/(double)(this->listAncestor->Length());

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::SplitColumn(char* buffer, TListE <String>* columns, char* characters) {

  if (!buffer || !columns || !characters) return false;

  char *part = strtok(buffer, characters);

  while (part) {
    String* cell = new String(part);
    cell->Trim();
    columns->Add(cell);
    part = strtok(NULL, characters);
  }

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::SplitColumn(char* buffer, TListE <String>* columns, const char* characters) {

  if (!buffer || !columns || !characters) return false;

  char *part = strtok(buffer, characters);

  while (part) {
    String* cell = new String(part);
    cell->Trim();
    columns->Add(cell);
    part = strtok(NULL, characters);
  }

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::CenterListByMatrix(TListE <AncestorMol>* representativeList, String* center = NULL) { 
  
  if (!center || !representativeList || !this->similarityMatrix) return;
  
  TListE <String>* listAncestorElement  = new TListE <String> ();

  representativeList->SetInitial();
  while (representativeList->SetNext()) 
    listAncestorElement->Add(new String(representativeList->GetCurrent()->ListIdAncestor()->GetFirst()));

  if (!center) {
    
    double** matrix = NULL;
    
    this->similarityMatrix->GetSubMatrix(listAncestorElement, matrix);

    double maxAverage = 0;
    long   position   = 0;
    
    for (int i = 0; i < listAncestorElement->Length(); i++)
      maxAverage += matrix[0][i];
    maxAverage /= listAncestorElement->Length();

    for (int i = 0; i < listAncestorElement->Length(); i++) {
      
      double average = 0;
      
      for (int j = 0; j < listAncestorElement->Length(); j++)
        average += matrix[i][j];
      average /= listAncestorElement->Length();      
      
      if (average > maxAverage) {
        maxAverage = average;
        position   = i;
      }
      
    }
    
    center = listAncestorElement->Get(position);
    
    if (matrix) {
      for (int i = 0; i < listAncestorElement->Length(); i++)
        if (matrix[i]) delete[] matrix[i];
      delete[] matrix;
    }

  }

  TNode <String>* centerNode = new TNode <String> ();
  
  centerNode->Info(center);

  listAncestorElement->OrderListCentered(SpaceListAncestor::ComputeMatrixSim, centerNode, this->similarityMatrix);

  for (int i = 0, k = 0; i < listAncestorElement->Length(); i++)
    for (int j = k; j < representativeList->Length(); j++)
      if (*(listAncestorElement->Get(i)) == *(representativeList->Get(j)->ListIdAncestor()->GetFirst())) {

        AncestorMol* temporal = representativeList->GetNode(k)->Info();
        representativeList->GetNode(k)->Info(NULL);
        representativeList->GetNode(k++)->Info(representativeList->GetNode(j)->Info());
        representativeList->GetNode(j)->Info(NULL);
        representativeList->GetNode(j)->Info(temporal);

      }

  centerNode->Info(NULL);

  if (centerNode)          delete centerNode;
  if (listAncestorElement) delete listAncestorElement;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::ListOriginalAncestor(TListE <AncestorMol>* ancestorList, TListE <AncestorMol>* representativeList, int level) {

  representativeList->Clear();
  
  ancestorList->SetInitial();
  while (ancestorList->SetNext()) {
    AncestorMol* originalAncestor = this->listAncestor->FirstOcurrence(SpaceListAncestor::EqualParents, ancestorList->GetCurrentNode(), &level);
    if (originalAncestor) representativeList->Add(originalAncestor);
  }
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol ListAncestorMol::operator=(ListAncestorMol& listAncestorMol) {

  *(this->filenameAncestor) = *(listAncestorMol.filenameAncestor);
  *(this->listAncestor)     = *(listAncestorMol.listAncestor);
  
  this->similarityMatrix = listAncestorMol.similarityMatrix;

  return *this;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
